/**
 * File  : Server.cc
 * Time  : 2015-01-05 16:07
 * Author: KashingLee
 * Ref   : Null
 */
#include <errno.h>
#include "Server.h"
#include <iostream>
#include"../WorkThreads.h"
#include "../ThreadMutex.h"
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <sys/stat.h>
using namespace std;

/*Server::Server() :client_sockfd_(-1) ,server_sockfd_(-1) ,size_(-1),\
                   recv_program_(0) ,program_num_(-1) ,set_(-1),\
                  controller(log_queue){
  memset(filename,0,sizeof(filename));
}*/

Server::Server(sa_family_t family, in_port_t port, in_addr_t addr, int type, \
								EventQueue<LogType>* log_queue)\
    :server_socket_(family,type), server_addr_(family, port, addr),\
     client_sockfd_(-1), server_sockfd_(-1), size_(-1),program_num_(-1),\
     recv_program_(0) ,set_(-1),log_queue_(log_queue){
  memset(filename,0,sizeof(filename));

}

Server::Server(sa_family_t family, in_port_t port, const char *addr, int type,\
								 EventQueue<LogType>* log_queue)\
    :server_socket_(family,type), server_addr_(family, port, addr),\
     client_sockfd_(-1), server_sockfd_(-1), size_(-1),program_num_(-1),\
     recv_program_(0) ,set_(-1),log_queue_(log_queue){
  memset(filename,0,sizeof(filename));

}
//Server::~Server();
void Server::Set(sa_family_t family, in_port_t port, in_addr_t addr, int type){
  server_socket_.set_type(type);
  server_socket_.set_family(family);
  server_addr_.SetFamily(family);
  server_addr_.SetPort(port);
  server_addr_.SetAddr(addr);
}

void Server::Set(sa_family_t family, in_port_t port, const char* addr, int type){
  server_socket_.set_type(type);
  server_socket_.set_family(family);
  server_addr_.SetFamily(family);
  server_addr_.SetPort(port);
  server_addr_.SetAddr(addr);
}

void Server::Init() {
  server_sockfd_ = server_socket_.Getfd();
  cout << "open " << server_sockfd_ << endl;
  int num = bind(server_sockfd_, server_addr_.addr_v4(), sizeof(struct sockaddr));
    //TODO
    cout <<"bind"<< num << endl;
  if( num < 0 ){
    cout <<"BIND failed and the reason is:"<<endl;
    cout << string(strerror(errno)) << endl;
    throw -1;
  }
  
  if ( listen(server_sockfd_, 2) < 0 ) {
    //TODO
    cout <<"LISTEN failed and the reason is:"<<endl;
    cout << string(strerror(errno)) << endl;
    throw -2;
  }
}

void Server::Accept() {
  fd_set rdfs ;
  fd_set wrfs ;
  int num =0 ;
  int max_fd;
  FD_ZERO(&rdfs);
  FD_ZERO(&wrfs);
  FD_SET(server_sockfd_,&rdfs);
  max_fd = server_sockfd_;
  socklen_t length; 
  while(1){
    cout << "Sellecting..." << endl;
    FD_SET(server_sockfd_,&rdfs); 
    num = select(max_fd+1,&rdfs,&wrfs,NULL,NULL);
    if(num ==-1){
      cout <<"SELLECT failed and the reason is:"<<endl;
      cout << string(strerror(errno)) << endl;
      throw 0;
    }
    cout << "the current fd stream number is : " << num << endl;
    cout << "select success... " << endl;
    
    for(int i=0;i<max_fd+1;i++){
      //cout << "now fd_isset wrfs = " << FD_ISSET(i,&wrfs)<<endl;
      //cout << "now fd_isset rdfs = " << FD_ISSET(i,&rdfs)<<endl;
      if(FD_ISSET(i,&wrfs)){
        cout << "i= " << i << endl;
        cout << "hello world!" <<endl;
        FD_CLR(i,&wrfs);
      } 
      else if(FD_ISSET(i,&rdfs)){
        cout << "max_fd "<<max_fd<<endl;
        cout <<"i= "<<i<<endl;
        if(i == server_sockfd_){
          cout << "now connecting... " << endl;
          length = (socklen_t)client_addr_.addr_len();
          client_sockfd_ = accept(server_sockfd_,\
                                  client_addr_.addr_v4(),\
                                  &length);
          cout <<client_sockfd_<<endl;
          if(client_sockfd_ < 0){
            cout <<"CHECK failed and the reason is:"<<endl;
            cout << string(strerror(errno)) << endl;
            throw 1;
          }
          FD_SET(client_sockfd_,&rdfs);
          FD_SET(client_sockfd_,&wrfs);
          if(max_fd < client_sockfd_){
            max_fd = client_sockfd_;
          }
          cout << "IP:" << client_addr_.AddrToString() << "port:" << client_addr_.Port() <<endl;
        }
        else if(i == client_sockfd_){
          //TODO
					cout<<"going to lock the mutex"<<endl;

					mutex_play_.Lock();
					mutex_set_.Lock();

          system("rm -rf ./program/1.xml");
          char flag_buffer[30];
          int size_in =0;
          int count =0;
          while(1) {
            memset(flag_buffer,0,30);
            if(RecvMsg(flag_buffer, sizeof(flag_buffer),client_sockfd_)<=0)break;
            cout << "recved :" << flag_buffer << endl;
            int ack =Decoder(flag_buffer,sizeof(flag_buffer),client_sockfd_);
            if(ack > 0){
              count++;
              memset(flag_buffer,0,30);
              if(ack == 5){     //time 
                //SetTime();                
                strcpy(flag_buffer,"ACK");
              }
              else if(ack ==6){ //ip 
                //SetIP();
                strcpy(flag_buffer,"ACK");
              }
              else if(ack ==2){ //file data
                if(recv_program_ ==1){
									DeleteFile();
                  strcpy(flag_buffer,"ACK");
                }
                else if(recv_program_ == program_num_ ){
                  recv_program_ = 0;
                  strcpy(flag_buffer,"ACK");
                }
                else 
                  strcpy(flag_buffer,"ACK");
                //sprintf(flag_buffer,"%d",recv_program_);
              }
              else {
                strcpy(flag_buffer,"ACK");
              }
              SendMsg(flag_buffer, sizeof(flag_buffer),client_sockfd_);
            }
            else {
              Throwerror(ack);
              memset(flag_buffer,0,30);
              sprintf(flag_buffer,"%d",ack);
              SendMsg(flag_buffer, sizeof(flag_buffer),client_sockfd_);
              break;
            }
          }

					mutex_play_.Unlock();
					mutex_set_.Unlock();

					cout<<"going to unlock the mutex"<<endl;
          cout <<"count = "<<count <<endl;
          close(i);
          FD_CLR(i,&rdfs);
          if(max_fd==i) max_fd--;
         
        }
      }
    }
  }
}

int  Server::Decoder( char* buffer,int size_in,int fd){
  if(strcmp(buffer,"data_size")==0){
    int num =0;
    memset(buffer,0,size_in);
    cout <<"size_in big: "<<size_in<<endl;
    num = RecvMsg(buffer,size_in/2,fd);
    if(num < 0) return -2;
    cout << "new size " << buffer <<endl;
    size_ = atoi(buffer);
    memset(buffer,0,size_in);
    num = RecvMsg(buffer,size_in/2,fd); 
    if(num < 0) return -2;
    cout << "new name "<< buffer <<endl;
    strcpy(filename,buffer);
    LogState(1,buffer);
    return 1;
  }
  else if(strcmp(buffer,"data")==0){
    if(size_ == -1){cout<<"WRONG!"<<endl;return -3;}
    if(program_num_ == -1){
      cout <<"have not receive program number!"<<endl;
      return -3;
    }
    recv_program_++;
    cout << "now recved " << recv_program_ << "'th file"<<endl;
    int num_all = 0;
    int num = 0;
    char* buffer_temp = new char[size_+1000];
    memset(buffer_temp,0,size_+1000);
    char filename_temp[30];
    sprintf(filename_temp,"%s/%s",root_path,filename);
    cout << filename_temp << endl;
    FILE *fp = fopen(filename_temp,"wb+");
    do{
      num = RecvMsg(buffer_temp,size_,fd);
      sleep(1);
      if(num>0){
        num_all+=num;
        fwrite(buffer_temp,sizeof(char),num,fp);
      }
    }while(num_all<size_);
    fflush(fp);
    fclose(fp);
    size_ = -1;
    delete buffer_temp;
    cout << "num_all = " <<num_all <<endl;
    return 2;
    LogState(2,buffer);
  }
  else if(strcmp(buffer,"set")==0){
    int num =0;
    memset(buffer,0,size_in);
    num = RecvMsg(buffer,size_in,fd);
    if(num < 0) return -4;
    cout << "program number = " << buffer <<endl;
    set_ = atoi(buffer);
		fstream fp_set;
		fp_set.open("./setting/setting.txt",std::fstream::out);
		fp_set<<set_;
		fp_set.close();
    if( set_ <0 ) return -4 ;
    LogState(3,buffer);
    return 3;
  }
  else if(strcmp(buffer,"prm_num")==0){
    int num =0;
    memset(buffer,0,size_in);
    num = RecvMsg(buffer,size_in,fd);
    if(num < 0) return -5;
    cout << "program number = " << buffer <<endl;
    program_num_ = atoi(buffer);
    LogState(4,buffer);
    return 4;
  }
  else if(strcmp(buffer,"time")==0){
    int num =0;
    memset(buffer,0,size_in);
    num = RecvMsg(buffer,size_in,fd);
    if(num < 0) return -6;
    cout << "now set time =  " << buffer << endl;
    time_ = buffer;
    LogState(5,buffer);
    return 5;
  }
  else if(strcmp(buffer,"ip")==0){
    int num =0;
    for (int x=0;x<4;x++){
      memset(buffer,0,size_in);
      num = RecvMsg(buffer,size_in,fd);
      cout <<"something wrong!"<<num<<endl;
      if(num < 0) return -7;
      switch(x){
      case 0 : ip_set_.address   = buffer;break;
      case 1 : ip_set_.netmask   = buffer;break;
      case 2 : ip_set_.network   = buffer;break;
      case 3 : ip_set_.broadcast = buffer;break;
      }
    }
    LogState(6,buffer);
    return 6;
  }
	else if(strcmp(buffer,"log")==0){
		time_t v_time;
	  time(&v_time);
	  tm* nowtime = localtime(&v_time);
		string log_base[3]={"./log/SETTING_LOGFILE","./log/NETTING_LOGFILE","./log/PLAYING_LOGFILE"};
		string log_name[3]={"SETTING_LOGFILE.txt","NETTING_LOGFILE.txt","PLAYING_LOGFILE.txt"};
		for(int i=0; i<3; i++){
			ostringstream oss;
			string filepath;
  		oss << log_base[i]<< "_" << nowtime->tm_year + 1900 << "_" <<
      	setw(2) << setfill('0')  << nowtime->tm_mon + 1 << "_" <<
      	setw(2) << setfill('0')  << nowtime->tm_mday;
			filepath=oss.str();
			FILE* file_ ;
			do{
			 file_ = fopen(filepath.c_str(),"rb+");
			}while(file_ <0);
	  	struct stat buf_pic;
	  	stat(filepath.c_str(),&buf_pic);

	  	int data_size= buf_pic.st_size;
	  	string data_suffix = log_name[i];
	  	char sendbuffer[30];
	 		char *set_buffer_temp = (char*)malloc(sizeof(char)*data_size);	
  		fread(set_buffer_temp,sizeof(char),data_size,file_ );
			int n=0;
  		memset(sendbuffer,0,sizeof(sendbuffer));
    	sprintf(sendbuffer," %-14d%s",data_size,data_suffix.c_str());
	    n=send(fd,sendbuffer,sizeof(sendbuffer),0);
	    if(n<0) perror("send size error\n");
   		int num=0;
   		num = send(fd,set_buffer_temp,data_size,MSG_WAITALL);//把数据传给服务器
		  if(num<0) perror("write data error!");
			free(set_buffer_temp);
	 		sleep(1);
		}
  	return 7;
    LogState(7,buffer);
	}
  else {
    cout << "Decoder Error"<<endl;
    return -1;
  }
}


int Server::SetTime(){
    string timeset = "date -s " + time_ + "&&hwclock --systohc";
    cout << timeset <<endl;
    int a = system(timeset.c_str()) ;
    if(a ==0){
      cout << "set time sucess!"<<endl;
      return 0;
    }
    else{
      cerr << "set time false! "<<endl;
      return -1;
    }
}

int Server::SetIP(){
   FILE *fp = fopen(NETWORK,"w+");
   string lo = "auto lo\niface lo inet loopback\n\nauto eth0\
                \niface eth0 inet static\
                \n    address "  +ip_set_.address+\
               "\n    netmask "  +ip_set_.netmask+\
               "\n    network "  +ip_set_.network+\
               "\n    broadcast "+ip_set_.broadcast;
   fwrite(lo.c_str(),sizeof(char),lo.size(),fp);
   system("/etc/init.d/networking restart");
   cout << lo <<endl;
   fclose(fp);
}


int Server::DeleteFile(){
    xmlDocPtr doc;           
    xmlNodePtr curNode;      
    xmlChar *szKey;        
    const char *szDocName = "./program/1.xml";
    int N=0;
    int i=0;
    doc = xmlReadFile(szDocName,"GB2312",XML_PARSE_RECOVER); 
    if (NULL == doc) 
    {  
       fprintf(stderr,"Document not parsed successfully. \n");     
       return -1; 
    } 
    curNode = xmlDocGetRootElement(doc); 
    if (NULL == curNode)
    { 
       fprintf(stderr,"empty document\n"); 
       xmlFreeDoc(doc); 
       return -1; 
    } 
    if (xmlStrcmp(curNode->name, BAD_CAST "root")) 
    {
       fprintf(stderr,"document of the wrong type, root node != root"); 
       xmlFreeDoc(doc); 
       return -1; 
    } 
    curNode = curNode->xmlChildrenNode;
    szKey=xmlNodeGetContent(curNode);
    string mode=reinterpret_cast<const char *>(szKey);
    if( mode == "INSERT" ) {
      cout <<"INSERT MODE"<<endl;
    }
    else if( mode =="NORMAL") {
      string location = "find ./program/* ! -name 1.xml -exec rm {} \\;";
      int a =system(location.c_str()) ;
      cout << "SYSTEM RM ACK = "<<a<<endl;
      cout <<"NORMAL MODE delete file now check"<<endl;
    }
    xmlFreeDoc(doc);
  return 0; 

}

void Server::Throwerror(int ack){
  if(ack ==-1)throw -1;
  else if(ack ==-2)throw -2;
  else if(ack ==-3)throw -3;
  else if(ack ==-4)throw -4;
  else if(ack ==-5)throw -5;
  else if(ack ==-6)throw -6;
  else if(ack ==-7)throw -7;
}
void Server::LogState(int ack,char* buffer){
  string temp = buffer;
  LogType log_type_;
  ostringstream oss;
  if(ack ==1){
    LOG_INFO(LOG_LEVEL_INFO) << "NET LOG ** " <<"RECEIVE NEW FILE : "<<temp; 
    LOG_ADD;
  }
  else if(ack == 2){
    LOG_INFO(LOG_LEVEL_INFO) << "NET LOG ** " <<"RECEIVING FILE "; 
    LOG_ADD;
  }
  else if(ack == 3){
    LOG_INFO(LOG_LEVEL_INFO) << "NET LOG ** " <<"RECEIVE NEW SET : "<<temp; 
    LOG_ADD;
  }
  else if(ack == 4){
    LOG_INFO(LOG_LEVEL_INFO) << "NET LOG ** " <<"RECEIVE PRM_NUM : "<<temp; 
    LOG_ADD;
  }
  else if(ack == 5){
    LOG_INFO(LOG_LEVEL_INFO) << "NET LOG ** " <<"RECEIVE NEW TIME : "<<temp; 
    LOG_ADD;
  }
  else if(ack ==6 ){
    LOG_INFO(LOG_LEVEL_INFO) << "NET LOG ** " <<"RECEIVE NEW IP : "<<temp; 
    LOG_ADD;
  }
	else if(ack==7){
    LOG_INFO(LOG_LEVEL_INFO) << "NET LOG ** " <<"SEND LOG FILE : "<<temp; 
    LOG_ADD;
	}
}
int  Server::SendMsg(char* flag_buffer, int size_in, int fd) {
  //cout << "SENDING . . . " << flag_buffer << endl;
  int num = send (fd,flag_buffer,size_in,0);
  if(num < 0){
    cout <<"SENDING failed and the reason is:"<<endl;
    cout << string(strerror(errno)) << endl;    
  }
  return num;
}

int  Server::RecvMsg(char* flag_buffer, int size_in, int fd) {
  int num = recv (fd,flag_buffer,size_in,MSG_WAITALL);
 // cout << "RECVING . . . " <<flag_buffer << endl;
  if(num < 0){
    cout <<"RECVING failed and the reason is:"<<endl;
    cout << string(strerror(errno)) << endl;    
  }
  return num;
}


